﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;

namespace Carbon.Web.Forms
{
    public enum ViewStatePersistanceMode { Client, Database, CompressedDatabase };

    public class FormPage : Page
    {
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            EnsureChildControls();
        }

        protected virtual ViewStatePersistanceMode ViewStatePersistanceMode
        {
            get
            {
                return Forms.ViewStatePersistanceMode.Client;
            }
        }

        private byte[] GetViewStateData(Object id, Guid key)
        {
            byte[] data = FormsContext.Current.PersistanceService.LoadBinaryData(id, key);

            return data;
        }

        private void DeserializeIdAndKey(String idAndKey, out String id, out Guid key)
        {
            String[] parts = idAndKey.Split(',');
            id = parts[0];
            key = new Guid(parts[1]);
        }

        protected override void SavePageStateToPersistenceMedium(object state)
        {
            if (ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.Client)
            {
                base.SavePageStateToPersistenceMedium(state);
            }
            else if (ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.Database || ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.CompressedDatabase)
            {
                String id = "";
                Object typedId = null;
                Guid key = Guid.Empty;

                if (IsPostBack)
                {
                    String idAndKey = this.Request["__ViewStateId"];
                    DeserializeIdAndKey(idAndKey, out id, out key);
                    typedId = InternalUtility.CompactDeserialize<Object>(id);
                }
                else
                {
                    key = Guid.NewGuid();
                }


                byte[] data = null;

                if (ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.Database)
                {
                    data = InternalUtility.CompactSerializeToByteArray(state);
                }
                else if (ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.CompressedDatabase)
                {
                    data = InternalUtility.Compress(InternalUtility.CompactSerializeToByteArray(state));
                }
                else
                {
                    throw new ArgumentOutOfRangeException("ViewStatePersistanceMode");
                }

                if (IsPostBack)
                {
                    FormsContext.Current.PersistanceService.UpdateBinaryData(typedId, key, data);
                }
                else
                {
                    id = InternalUtility.CompactSerialize(FormsContext.Current.PersistanceService.StoreBinaryData(key, data));
                }

                this.ClientScript.RegisterHiddenField("__ViewStateId", ConvertInvariant.ToString(id) + "," + ConvertInvariant.ToString(key));
            }
            else
            {
                throw new ArgumentOutOfRangeException("ViewStatePersistanceMode");
            }
        }

        protected override object LoadPageStateFromPersistenceMedium()
        {
            if (ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.Client)
            {
                return base.LoadPageStateFromPersistenceMedium();
            }
            else if (ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.Database || ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.CompressedDatabase)
            {
                String id = "";
                Guid key;

                if ((IsPostBack) == false) throw new InvalidOperationException("(IsPostBack) == false");

                String idAndKey = this.Request["__ViewStateId"];

                DeserializeIdAndKey(idAndKey, out id, out key);

                Object storeId = InternalUtility.CompactDeserialize<Object>(id);
                byte[] data = GetViewStateData(storeId, key);

                if (ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.Database)
                {
                    return InternalUtility.CompactDeserializeFromByteArray<object>(data);
                }
                else if (ViewStatePersistanceMode == Forms.ViewStatePersistanceMode.CompressedDatabase)
                {
                    return InternalUtility.CompactDeserializeFromByteArray<object>(InternalUtility.Decompress(data));
                }
                else
                {
                    throw new ArgumentOutOfRangeException("ViewStatePersistanceMode");
                }
            }
            else
            {

                throw new ArgumentOutOfRangeException("ViewStatePersistanceMode");
            }
        }
    }
}
